home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************/
- /* */
- /* */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* *************** *************** */
- /* ***************** ***************** */
- /* *************** *************** */
- /* ***** ***** TheNet */
- /* ***** ***** Portable. Compatible. */
- /* ***** ***** Public Domain */
- /* ***** ***** G8KBB */
- /* */
- /* This software is public domain ONLY for non commercial use */
- /* */
- /* */
- /*****************************************************************************/
-
- /* Level 3, Internet Gateway */
- /* Version 1.00 */
- /* Dave Roberts G8KBB, 7, Rowanhayes Close, Ipswich, England */
- /* 10-April-91 */
- /* This software is released into the public domain on the understanding
- * that it is to be used only for non life threatening, amateur, non
- * commercial purposes only.
- * It has been written expressly for use in self tuition of
- * people in amateur radio communications only. It is NOT claimed that this
- * software works correctly.
- *
- * USELONG, if defined, causes long integers to be used where appropriate
- * so failing to define it will avoid longs completely !
- *
- * September 1993 - released as TheNet X-1J
- */
-
- #include "all.h"
- #include "tntyp.h" /* Definition of structures */
- #include "ip.h"
- #include "icmp.h"
- #ifdef BANKED
- #define EXTERN extern
- #else
- #define EXTERN
- #endif
-
- #include "ipv.h"
-
- /*---------------------------------------------------------------------------*/
- /* Strings etc */
-
- /* These are the interface handlers.
- * Number Interface
- * 0 Netrom
- * 1 port 0 AX.25
- * 2 port 1 AX.25
- *
- * The order MUST match the names in if_names[] in tnl7ip.c
- */
-
- I_FACE interfaces[] =
- {
- #ifdef MOD_MTU
- nr_iface, &mtu_ipn, ARP_NETROM, 0,
- l2_iface, &mtu_ip0, ARP_AX25, HDLCPORT,
- l2_iface, &mtu_ip1, ARP_AX25, ASYNPORT,
- #else
- nr_iface, 256-20, ARP_NETROM, 0,
- l2_iface, 256, ARP_AX25, HDLCPORT,
- l2_iface, 256, ARP_AX25, ASYNPORT,
- #endif
- };
-
- char nodigi[] = { '\000' };
- char QST[] = { 'Q','S','T',' ',' ',' ','\140' };
-
- /* ***************************************************************************
- * Function : ipinit
- *
- * Inputs : none
- *
- * Returns : none
- *
- * Operation : Initialisation of IP gateway on reset of the TNC
- *
- * -------------------------------------------------------------------------*/
-
- VOID ipinit() /* Router initialisation */
- {
- register int i;
-
- inithd(&iprxfl);
- inithd(&arprxfl);
-
- if (!iswarm()) /* Warmstart then skip */
- {
- inithd(&IP_Routes);
- inithd(&Arp_tab);
- #ifdef USELONG
- my_ip_addr.Long = DEFMYIPADDR.Long; /* node IP address */
- bcast_ip_addr.Long = DEFIPBCAST.Long; /* broadcast addr */
- #else
- my_ip_addr.Short[1] = DEFMYIPADDR.Short[1]; /* node IP */
- my_ip_addr.Short[0] = DEFMYIPADDR.Short[0]; /* ..address*/
- bcast_ip_addr.Short[1] = DEFIPBCAST.Short[1]; /* broadcast*/
- bcast_ip_addr.Short[0] = DEFIPBCAST.Short[0]; /* ..address*/
- #endif
- for( i=0; i<=NUMIPMIB; i++ )
- Ip_mib[i].value.integer = 0; /* clear IP stats */
- ipL2Modes = DEFIPL2MODES; /* l2 modes */
- ARPrunning = ipForwarding = DEFIPENABLE;/* enable ip router */
- ipDefaultTTL = DEFIPTTL; /* set default ttl */
- ipReasmTimeout = TLB; /* reasm timeout */
- ARPcounter = ARPtimer = 60;
- }
- else /* Warmstart */
- {
- }
- IP_Route_Cache.route = NULLROUTE; /* clear route cache */
- }
-
- /* ***************************************************************************
- * Function : IP server programme. Called by main scheduler
- *
- * Inputs : None
- *
- * Returns : None
- *
- * Operation : Reads all frames from ip receive queue and handles them.
- * Then calls ARP protocol handler with its frames
- * -------------------------------------------------------------------------*/
- VOID ipserv()
- {
- register mhtyp *mbhd;
-
- /* Firstly, run through the queued IP frames
- */
- while ((mbhd = (mhtyp *)iprxfl.lnext) != (mhtyp *) &iprxfl)
- {
- unlink( mbhd );
- #ifdef PK96
- sta_led_on();
- #endif
- ip_route( mbhd ); /* pass to IP router routine */
- #ifdef PK96
- sta_led_off();
- #endif
- dealmb( mbhd );
- }
- /* Now run through the queued ARP frames
- */
- while ((mbhd = (mhtyp *)arprxfl.lnext) != (mhtyp *) &arprxfl)
- {
- unlink( mbhd );
- arp_service( mbhd ); /* pass to IP router routine */
- dealmb( mbhd );
- }
- }
-
-
- /* ***************************************************************************
- * Function : IP router for a single frame. Called by ip server
- *
- * Inputs : Pointer to frame to be routed
- *
- * Returns : None
- *
- * Operation : Forwards frame or returns an error ( ICMP ) frame.
- * Fragments the frame if sub layer demands it
- * -------------------------------------------------------------------------*/
- VOID ip_route( frame ) /* Internet server */
- mhtyp *frame;
- {
- register int i; /* a counter of general nature */
- register mhtyp *mbhd = frame; /* pointer to frame using a register*/
- register mhtyp *tbp; /* pointer to frame for outputting */
- char *rxnxt; /* temp for saving mbhd position */
- #ifndef BANKED
- static IP ip; /* structure for decoded ip header */
- #endif
- int strict; /* option sets for strict routing */
- ipaddr gateway; /* addr of next IP router for frame */
- IP_ROUTE *rp; /* pointer used in finding route */
- unsigned length; /* length of data portion of frame */
- unsigned offset; /* offset in fragmentation routine */
- BOOLEAN rxbroadcast; /* set denotes broadcast frame */
- BOOLEAN mf_flag; /* more flag in fragmentation */
- unsigned char *opt, *ptr; /* pointers in option handling */
- unsigned char opt_len; /* length in option handling */
- unsigned ip_len; /* ip header length */
- unsigned mtu; /* max port packet size for output */
-
- if(((unsigned char)mbhd->pid != PID_IP) || !ipForwarding )
- return;
- rxnxt = mbhd->nxtchr; /* Save pointers to IP hdr start */
- ip_len = getchr( mbhd ); /* get length & version byte*/
- ip.version = ( ip_len >> 4 ) & 0x0f; /* extract version number */
- ip_len = ( ip_len & 0x0f ) << 2; /* and correct length */
- mbhd->nxtchr = rxnxt; /* reinstate the pointer */
- if( ( mbhd->putcnt - (--mbhd->getcnt) ) < IPLEN
- ||
- ip_len < IPLEN
- ||
- ip.version != IPVERSION
- ||
- cksum( NULLHEADER, mbhd, ip_len ) != 0 )
- {
- ipInHdrErrors++;
- return;
- }
-
- /* Now extract frame IP header
- * This is akin to ntohip() in NOS
- */
- getchr( mbhd ); /* skip length/version */
- ip.tos = getchr( mbhd );
- ip.length = get16( mbhd );
- ip.id = get16( mbhd );
- ip.offset = get16( mbhd );
- ip.flags.mf = ( ip.offset & 0x2000 ) ? 1 : 0;
- ip.flags.df = ( ip.offset & 0x4000 ) ? 1 : 0;
- ip.offset = ( ip.offset & 0x1fff ) << 3;
- ip.ttl = getchr( mbhd );
- ip.protocol = getchr( mbhd );
- ip.checksum = get16( mbhd );
- ip.source.Short[1] = get16( mbhd );
- ip.source.Short[0] = get16( mbhd );
- ip.dest.Short[1] = get16( mbhd );
- ip.dest.Short[0] = get16( mbhd );
-
- /* If this is a broadcast packet, set flag
- * Note we do not do port addressing here !
- */
- rxbroadcast = is_broadcast_address( &ip.dest );
-
- /* extract optional options from frame
- */
- if( (ip.optlen = ip_len - IPLEN ) != 0 )
- for( i=0; i < ip.optlen; i++ )
- ip.options[i] = getchr( mbhd );
- length = ip.length - ip_len;
- /* trim_mbuf( don't bother with this in this version ! );
- */
- if( !rxbroadcast && nmbfre < 256 )
- icmp_output( &ip, mbhd, ICMP_QUENCH, 0, NULLICMP );
-
- /* handle options here
- */
- strict = 0;
- for( opt = ip.options; opt < &ip.options[ip.optlen]; opt += opt_len )
- {
- opt_len = opt[1];
- switch( opt[0] & OPT_NUMBER )
- {
- case IP_EOL:
- goto no_opt;
- case IP_NOOP:
- opt_len = 1;
- break;
- case IP_SSROUTE:
- strict = 1;
- case IP_LSROUTE:
- if( !is_my_ip_addr( &ip.dest ) )
- break;
- if( opt[2] >= opt_len )
- break;
- ptr = opt+opt[2]-1;
- for( i=0; i<4; i++ )
- {
- ip.dest.Bytes[3-i] = ptr[i];
- ptr[i] = my_ip_addr.Bytes[3-i];
- }
- opt[2] += 4;
- break;
- case IP_RROUTE:
- if( opt[2] >= opt_len )
- {
- if( !rxbroadcast )
- {
- union icmp_args icmp_args;
-
- icmp_args.pointer = IPLEN+opt-ip.options;
- icmp_output(&ip,mbhd,ICMP_PARAM_PROB,0,&icmp_args);
- }
- return;
- }
- ptr = opt+opt[2]-1;
- for( i=0; i<4; i++ )
- ptr[i] = my_ip_addr.Bytes[3-i];
- opt += 4;
- break;
- }
- }
- no_opt:
- if( ( is_my_ip_addr( &ip.dest ) ) || rxbroadcast )
- {
- if( !rxbroadcast && !ip.flags.mf && ip.offset == 0 &&
- ip.protocol == ICMP_PTCL )
- {
- icmp_input( &ip, mbhd );
- ipInReceives++;
- return;
- }
- else
- {
- if( !rxbroadcast )
- icmp_output( &ip, mbhd, ICMP_DEST_UNREACH,
- ICMP_PROT_UNREACH, NULLICMP );
- ipInUnknownProtos++;
- return;
- }
- }
-
- /* if( i_iface != NULLIF ) etc etc */
-
- ipForwDatagrams++;
-
- /* timeout - kill & return error frame to sender
- */
- if( --ip.ttl == 0 )
- {
- icmp_output( &ip, mbhd, ICMP_TIME_EXCEED, 0, NULLICMP );
- ipInHdrErrors++;
- return;
- }
-
- /* find entry in routing table for this frame.
- * If there isn't one - then return an error & trash frame
- */
- if( ( rp = rt_find( &ip.dest ) ) == NULLROUTE )
- {
- icmp_output( &ip, mbhd, ICMP_DEST_UNREACH,
- ICMP_HOST_UNREACH, NULLICMP );
- ipOutNoRoutes++;
- return;
- }
-
- /* rp->uses++ */
- /* redirection goes here if wanted */
-
- /* Compute the next IP router to send to ( ie the gateway )
- * If the route table entry has no gateway, use destination
- * If the gateway is not the destination, and strict routing
- * has been called for, then error !
- */
- #ifdef USELONG
- gateway.Long = rp->gateway.Long == 0L ? ip.dest.Long : rp->gateway.Long;
- if( strict && gateway.Long != ip.dest.Long )
- #else
- i = (rp->gateway.Short[0] == 0) && ( rp->gateway.Short[1] == 0 );
- gateway.Short[0] = i ? ip.dest.Short[0] : rp->gateway.Short[0];
- gateway.Short[1] = i ? ip.dest.Short[1] : rp->gateway.Short[1];
- if( strict && !( ( gateway.Short[0] == ip.dest.Short[0] ) &&
- ( gateway.Short[1] == ip.dest.Short[1] ) ) )
- #endif
- {
- icmp_output( &ip, mbhd, ICMP_DEST_UNREACH,
- ICMP_ROUTE_FAIL, NULLICMP );
- ipOutNoRoutes++;
- return;
- }
-
- /* bomb out if a funny has happened ( to preserve node integrity )
- */
- if( rp->interface >= MAXINTERFACES )
- return;
-
- /* mtu for interface determines whether frame needs fragmentation
- */
- #ifdef MOD_MTU
- mtu = *(interfaces[rp->interface].mtu);
- #else
- mtu = interfaces[rp->interface].mtu;
- #endif
- if( ip.length <= mtu )
- {
- tbp = htonip( &ip, mbhd, 0 );
- /* if( tbp == NULLBUF )
- return;
- */ (*interfaces[rp->interface].func)( tbp, rp->interface,
- &gateway, ip.tos );
- return;
- }
-
- /* fragmentation needed for here on.
- * First point -if it is marked don't fragment, we have a problem
- */
- if( ip.flags.df )
- {
- union icmp_args icmp_args;
-
- icmp_args.mtu = mtu;
- icmp_output(&ip,mbhd,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,&icmp_args );
- ipFragFails++;
- return;
- }
-
- /* prepare for fragmentation & go for it !
- */
- offset = ip.offset;
- mf_flag = ip.flags.mf;
- while( length != 0 )
- {
- unsigned fragsize;
-
- ip.offset = offset;
- if( length + ip_len <= mtu )
- {
- fragsize = length;
- ip.flags.mf = mf_flag;
- }
- else
- {
- fragsize = (mtu - ip_len ) & 0xfff8;
- ip.flags.mf = 1;
- }
- ip.length = fragsize + ip_len;
- tbp = htonip( &ip, NULLBUF, 0 );
- for( i=fragsize; i != 0; i-- )
- putchr( getchr( mbhd ), tbp );
- (*interfaces[rp->interface].func)( tbp, rp->interface,
- &gateway, ip.tos );
- ipFragCreates++;
- offset += fragsize;
- length -= fragsize;
- }
- ipFragOKs++;
- return;
- }
-
- /* ***************************************************************************
- * Function : Determine if this address is my address
- *
- * Inputs : pointer to address to be checked
- *
- * Returns : TRUE if addresses match and an address has been set
- * FALSE if my address zero or no address match
- *
- * Operation :
- * -------------------------------------------------------------------------*/
- is_my_ip_addr( address )
- register ipaddr *address;
- {
- #ifdef USELONG
- return( my_ip_addr.Long != 0L && my_ip_addr.Long == address->Long );
- #else
- if( (my_ip_addr.Short[0] == 0) && (my_ip_addr.Short[1] == 0) )
- return( 0 );
- return( (my_ip_addr.Short[0] == address->Short[0]) &&
- (my_ip_addr.Short[1] == address->Short[1]) );
- #endif
- }
-
- /* ***************************************************************************
- * Function : Check whether this address is the IP broadcast_ip address
- *
- * Inputs : Pointer to IP address
- *
- * Returns : TRUE if my address set and addresses match exactly
- * FALSE otherwise
- *
- * Operation :
- * -------------------------------------------------------------------------*/
- is_broadcast_address( address )
- register ipaddr *address;
- {
- #ifdef USELONG
- return( bcast_ip_addr.Long != 0L && bcast_ip_addr.Long == address->Long );
- #else
- if( (bcast_ip_addr.Short[0] == 0) && (bcast_ip_addr.Short[1] == 0) )
- return( 0 );
- return( (bcast_ip_addr.Short[0] == address->Short[0]) &&
- (bcast_ip_addr.Short[1] == address->Short[1]) );
- #endif
- }
-
-
- /* ***************************************************************************
- * Function : Try to find an entry in routing table for given target
- *
- * Inputs : Pointer to IP address of target
- *
- * Returns : Either a pointer to the table entry or a null pointer if none
- *
- * Operation : First check the cache & return it if it is the one
- * Then search the table which is stored in descending order
- * of the number of significant bits, masking our address as
- * we go.
- * -------------------------------------------------------------------------*/
- IP_ROUTE *rt_find( target )
- register ipaddr *target;
- {
- register IP_ROUTE_MB *iprp;
- ipaddr temp;
- register unsigned bits;
-
- #ifdef USELONG
- if( IP_Route_Cache.target.Long == target->Long &&
- IP_Route_Cache.route != NULLROUTE )
- return( IP_Route_Cache.route );
-
- temp.Long = target->Long;
- #else
- if( (IP_Route_Cache.target.Short[0] == target->Short[0] ) &&
- (IP_Route_Cache.target.Short[1] == target->Short[1] ) &&
- IP_Route_Cache.route != NULLROUTE )
- return( IP_Route_Cache.route );
-
- temp.Short[0] = target->Short[0];
- temp.Short[1] = target->Short[1];
- #endif
- bits = 32;
- for( iprp = (IP_ROUTE_MB *)IP_Routes.lnext;
- iprp != (IP_ROUTE_MB *)&IP_Routes.lnext;
- iprp = (IP_ROUTE_MB *)iprp->link.lnext )
- {
- #ifdef USELONG
- if( bits > iprp->route.bits )
- temp.Long &= ~0L << ( 32 - ( bits = iprp->route.bits ) );
- if( iprp->route.dest.Long == temp.Long )
- {
- IP_Route_Cache.target.Long = target->Long;
- return ( (IP_Route_Cache.route = &iprp->route) );
- }
- #else
- if( bits > iprp->route.bits )
- ip_mask( &temp, ( bits = iprp->route.bits ) );
- if( (iprp->route.dest.Short[0] == temp.Short[0]) &&
- (iprp->route.dest.Short[1] == temp.Short[1]) )
- {
- IP_Route_Cache.target.Short[0] = target->Short[0];
- IP_Route_Cache.target.Short[1] = target->Short[1];
- return ( (IP_Route_Cache.route = &iprp->route) );
- }
- #endif
- }
- return( NULLROUTE );
- }
-
- /* ***************************************************************************
- * Function : Convert host IP format header to network format
- *
- * Inputs : pointer to header, buffer for data bytes & ckecksum flag
- *
- * Returns : pointer to the new buffer in network format
- *
- * Operation : Creates a new buffer,
- * Transfers the header into it,
- * and unless the data buffer is a null pointer, copies data
- * -------------------------------------------------------------------------*/
- mhtyp *htonip( iphdr, data, cflag )
- register IP *iphdr;
- mhtyp *data;
- BOOLEAN cflag;
- {
- unsigned hdr_len;
- register unsigned i;
- register mhtyp *bufpoi;
- unsigned fl_offs;
- unsigned checksum;
- char *ptr, *cksum_ptr;
-
- hdr_len = IPLEN + iphdr->optlen;
- bufpoi = (mhtyp *)allocb();
- putchr( ( IPVERSION << 4 ) | ( hdr_len >> 2 ), bufpoi );
- putchr( iphdr->tos, bufpoi );
- put16( iphdr->length, bufpoi );
- put16( iphdr->id, bufpoi );
- fl_offs = iphdr->offset >> 3;
- if( iphdr->flags.df )
- fl_offs |= 0x4000;
- if( iphdr->flags.mf )
- fl_offs |= 0x2000;
- put16( fl_offs, bufpoi );
- putchr( iphdr->ttl, bufpoi );
- putchr( iphdr->protocol, bufpoi );
- cksum_ptr = bufpoi->nxtchr;
- put16( 0, bufpoi );
- put16( iphdr->source.Short[1], bufpoi );
- put16( iphdr->source.Short[0], bufpoi );
- put16( iphdr->dest.Short[1], bufpoi );
- put16( iphdr->dest.Short[0], bufpoi );
- for( i=0; i< iphdr->optlen; i++ )
- putchr( iphdr->options[i], bufpoi );
- ptr = bufpoi->nxtchr;
- i = bufpoi->putcnt;
- rwndmb( bufpoi );
- checksum = cflag ? iphdr->checksum : cksum(NULLHEADER,bufpoi,hdr_len);
- bufpoi->nxtchr = cksum_ptr;
- bufpoi->putcnt = 10;
- put16( checksum, bufpoi);
- bufpoi->nxtchr = ptr;
- bufpoi->putcnt = i;
- if( data != NULLBUF )
- {
- #ifdef MODIFIED
- mhtyp_copy( data, bufpoi );
- #else
- i = data->putcnt - data->getcnt;
- while( i-- )
- putchr( getchr( data ) , bufpoi );
- #endif
- }
- return( bufpoi );
- }
-
- /* ***************************************************************************
- * Function : Send an IP datagram.
- * Modelled after the example interface on p 32 of RFC 791
- *
- * Inputs : er, read the comments below !
- *
- * Returns : nothing of any significance in this implementation
- *
- * Operation : Create network format header, append data to it to
- * make a frame that looks like any other frame received
- * and drop it back into the ip receive queue for ip_route
- * -------------------------------------------------------------------------*/
- int ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
- ipaddr *source; /* source address */
- ipaddr *dest; /* Destination address */
- unsigned protocol; /* Protocol */
- unsigned tos; /* Type of service */
- unsigned ttl; /* Time-to-live */
- mhtyp *bp; /* Data portion of datagram */
- unsigned short length; /* Optional length of data portion */
- unsigned short id; /* Optional identification */
- unsigned df; /* Don't-fragment flag */
- {
- register mhtyp *tbp;
- IP ip; /* Pointer to IP header */
- register IP *ipptr = &ip;
- #ifndef BANKED
- static unsigned short id_cntr; /* Datagram serial number */
- #endif
-
- ipOutRequests++;
-
- /* if(*source == INADDR_ANY) AAAARRRRRGGGHHHHH !!!
- source.Long = my_ip_addr.Long;
- */ if(length == 0 && bp != NULLBUF)
- length = bp->putcnt - bp->getcnt;
-
- /* Fill in IP header */
- ipptr->tos = tos;
- ipptr->length = IPLEN + length;
- ipptr->id = ( id == 0 ) ? id_cntr++ : id;
- ipptr->offset = 0;
- ipptr->flags.mf = 0;
- ipptr->flags.df = df;
- ipptr->ttl = ( ttl == 0 ) ? ipDefaultTTL : ttl;
- ipptr->protocol = protocol;
- #ifdef USELONG
- ipptr->source.Long = source->Long;
- ipptr->dest.Long = dest->Long;
- #else
- ipptr->source.Short[0] = source->Short[0];
- ipptr->source.Short[1] = source->Short[1];
- ipptr->dest.Short[0] = dest->Short[0];
- ipptr->dest.Short[1] = dest->Short[1];
- #endif
- ipptr->optlen = 0;
- tbp = htonip(&ip,bp,0);
- dealmb(bp);
- /* if( tbp == NULLBUF)
- return( -1 );
- */ tbp->pid = PID_IP;
- rwndmb( tbp );
- relink( tbp, iprxfl.lprev );
- return(0);
- }
-
- /* ***************************************************************************
- * Function : ip router interface handler for netrom interface
- *
- * Inputs : frame to send, interface handle, gateway address & flags
- *
- * Returns : nothing
- *
- * Operation : The frame is sent to the netrom interface, assuming that
- * the arp table contains an entry for the gateway that will
- * tell us what node callsign to use !
- * The frame is sent by appending it to the L3 send queue
- * -------------------------------------------------------------------------*/
- unsigned nr_iface( mhbp, iface, gateway, tos )
- mhtyp *mhbp;
- unsigned iface;
- ipaddr *gateway;
- unsigned tos;
- {
- register unsigned i;
- register mhtyp *mb;
- register ARP_TAB *arp;
-
- /* check if there is a netrom entry in arp table. If so, then
- * check if there is a corresponding netrom node entry and set
- * despoi to point to its identity
- */
- if( (arp = res_arp( gateway, ARP_NETROM ) ) != NULLARP &&
- iscall( arp->callsign ) )
- {
- l4pidx = l4pcid = NR_PROTO_IP; /* netrom IP family */
- l4ahd2 = l4ahd3 = 0; /* these are unused for IP */
- l4aopc = NR4_OP_PID; /* netrom proto extension */
- mb = gennhd(); /* create a L4 & L3 header */
- rwndmb( mhbp ); /* rewind to start for send */
- #ifdef MODIFIED
- mhtyp_copy( mhbp, mb );
- #else
- i = mhbp->putcnt - mhbp->getcnt;/* then copy frame onto hdr */
- while( i-- )
- putchr( getchr( mhbp ), mb );
- #endif
- mb->l2lnk = despoi; /* link points to dest node */
- relink( mb, l3txl.lprev ); /* and queue it ! */
- }
- dealmb( mhbp );
- }
-
- /* ***************************************************************************
- * Function : AX.25 handler for ip router
- *
- * Inputs : as for above interface to netrom
- *
- * Returns : nothing
- *
- * Operation : determine if dg or vc. Queue for sending as appropriate
- * -------------------------------------------------------------------------*/
- unsigned l2_iface( mhbp, iface, gateway, tos )
- mhtyp *mhbp;
- unsigned iface;
- ipaddr *gateway;
- unsigned tos;
- {
- register ARP_TAB *arp;
- register unsigned cnt;
- unsigned port;
- register l2ltyp *l2poi;
-
- /* determine tnc port number, rewind buffer & set PID to IP
- */
- port = interfaces[iface].port;
- rwndmb( mhbp );
- mhbp->pid = PID_IP;
-
- /* find the arp entry. Die if none !
- */
- if( (arp = res_arp( gateway, ARP_AX25 ) ) == NULLARP )
- {
- arp_request( gateway, ARP_AX25, port );
- dealmb( mhbp );
- }
-
- /* Now check to see if we are going to DG or VC it
- */
- else if( (arp->dgmode & 1) || (( arp->dgmode == 0 ) && ( tos & DELAY ||
- ( !( tos & RELIABILITY ) && ( ipL2Modes & (1<<port))))))
- {
- sdui( nodigi, arp->callsign, myid, port, mhbp );
- dealmb( mhbp );
- }
- else /* virtual circuit */
- {
- /* Need to find current L2 connection or need to make one
- */
- for( l2poi = 0, cnt = 0, lnkpoi = &lnktbl[0];
- cnt < MAXL2L; ++cnt, ++lnkpoi )
- {
- if( lnkpoi->state != 0 )
- {
- if( cmpid( arp->callsign, lnkpoi->dstid ) &&
- cmpid( myid, lnkpoi->srcid ) &&
- lnkpoi->liport == port )
- break;
- }
- else if( (l2poi == 0 ) && ( lnkpoi->srcid[0] == 0 ) )
- l2poi = lnkpoi;
- }
-
- /* either we have it or we are at the end, with no space
- * or a pointer to the first free entry in the link list
- */
- if( cnt == MAXL2L )
- {
- if( l2poi != 0 )
- {
- lnkpoi = l2poi;
- cpyid( lnkpoi->srcid, myid );
- cpyid( lnkpoi->dstid, arp->callsign );
- cpyidl(lnkpoi->viaid, nodigi );
- lnkpoi->liport = port;
- newlnk();
- }
- else /* no link and no space for one */
- {
- dealmb( mhbp );
- return;
- }
- }
- lnkpoi->tosend++;
- relink( mhbp, lnkpoi->sendil.lprev );
- }
- }
-
-
- /* ***************************************************************************
- * Function : find an arp entry for a given target and hardware type
- *
- * Inputs : pointer to internet address and a hardware ( arp ) type
- *
- * Returns : pointer to entry in arp table or a null pointer
- *
- * Operation : linear search of table looking for a match
- * -------------------------------------------------------------------------*/
- ARP_TAB *res_arp( target, hwtype )
- register unsigned hwtype;
- register ipaddr *target;
- {
- register ARP_TAB_MB *arprp;
-
- for( arprp = (ARP_TAB_MB *)Arp_tab.lnext;
- arprp != (ARP_TAB_MB *)&Arp_tab.lnext;
- arprp = (ARP_TAB_MB *)arprp->link.lnext )
- if( hwtype == arprp->arp.hwtype &&
- #ifdef USELONG
- arprp->arp.dest.Long == target->Long )
- #else
- arprp->arp.dest.Short[0] == target->Short[0] &&
- arprp->arp.dest.Short[1] == target->Short[1] )
- #endif
- return( &arprp->arp );
- return( NULLARP );
- }
-
- /* ***************************************************************************
- * Function : Get a sixteen bit word from buffer
- *
- * Inputs : pointer to buffer
- *
- * Returns : unsigned integer
- *
- * Operation : reads two bytes into a structure & swaps in process.
- * -------------------------------------------------------------------------*/
- unsigned get16( mbhd )
- register mhtyp *mbhd;
- {
- union {
- unsigned Short;
- unsigned char Bytes[2];
- } regs;
-
- regs.Bytes[1] = getchr( mbhd );
- regs.Bytes[0] = getchr( mbhd );
- return( regs.Short );
- }
-
- /* ***************************************************************************
- * Function : Put an unsigned integer as two bytes in buffer
- *
- * Inputs : value to put and pointer to buffer
- *
- * Returns : nothing
- *
- * Operation :
- * -------------------------------------------------------------------------*/
- VOID put16( value, mbhd )
- register unsigned value;
- register mhtyp *mbhd;
- {
- union {
- unsigned Short;
- unsigned char Bytes[2];
- } regs;
-
- regs.Short = value;
- putchr( regs.Bytes[1], mbhd );
- putchr( regs.Bytes[0], mbhd );
- }
-
-
- /* ***************************************************************************
- * Function : Return an ICMP response to the sender of a datagram.
- * Unlike most routines, the callER frees the mbuf.
- *
- * Inputs : pointer to offending ip header, data, icmp codes & params
- *
- * Returns : nothing in this version !
- *
- * Operation : Did you ever hear the one about the vampire rabbit ?
- * Note lots of standard icmp bits are commented out.
- * -------------------------------------------------------------------------*/
- int icmp_output(ip,data,type,code,args)
- IP *ip; /* Header of offending datagram */
- register mhtyp *data; /* Data portion of datagram */
- unsigned type,code; /* Codes to send */
- union icmp_args *args;
- {
- mhtyp *bp, *bp2;
- ICMP icmp; /* ICMP protocol header */
- unsigned short length; /* Total length of reply */
- register unsigned short i;
- char *rxnxt;
-
- if(ip == NULLIP)
- return(-1);
- if( (unsigned char)ip->protocol == ICMP_PTCL)
- {
- /* Peek at type field of ICMP header to see if it's safe to
- * return an ICMP message
- */
- rxnxt = data->nxtchr;
- i = getchr( data ) & 0xff;
- data->nxtchr = rxnxt;
- data->getcnt--;
- switch( i )
- {
- case ICMP_ECHO_REPLY:
- case ICMP_ECHO:
- case ICMP_TIMESTAMP:
- case ICMP_TIME_REPLY:
- case ICMP_INFO_RQST:
- case ICMP_INFO_REPLY:
- break; /* These are all safe */
- default:
- /* Never send an ICMP error message about another
- * ICMP error message!
- */
- return(-1);
- }
- }
- /* Compute amount of original datagram to return.
- * We return the original IP header, and up to 8 bytes past that.
- */
- i = data->putcnt - data->getcnt;
- if( i > 8 ) i = 8;
- length = i + ICMPLEN + IPLEN + ip->optlen;
-
- /* Recreate and tack on offending IP header */
- bp = htonip(ip, NULLBUF, 1);
-
- /* if( data == NULLBUF)
- {
- icmpOutErrors++;
- return(-1);
- }
- */
- /* Take excerpt from data portion */
- while( i-- ) /* i set in above !!! */
- putchr( getchr( data ), bp );
- icmp.type = type;
- icmp.code = code;
- icmp.args.unused = 0;
-
- switch( type )
- {
- /* case ICMP_ECHO:
- icmpOutEchos++;
- break;
- case ICMP_ECHO_REPLY:
- icmpOutEchoReps++;
- break;
- case ICMP_INFO_RQST:
- break;
- case ICMP_INFO_REPLY:
- break;
- case ICMP_TIMESTAMP:
- icmpOutTimestamps++;
- break;
- case ICMP_ADDR_MASK:
- icmpOutAddrMasks++;
- break;
- case ICMP_ADDR_MASK_REPLY:
- icmpOutAddrMaskReps++;
- break;
- case ICMP_TIME_EXCEED:
- icmpOutTimeExcds++;
- break;
- case ICMP_QUENCH:
- icmpOutSrcQuenchs++;
- break;
- */ case ICMP_PARAM_PROB:
- /* icmpOutParmProbs++;
- */ icmp.args.pointer = args->pointer;
- break;
- case ICMP_REDIRECT:
- /* icmpOutRedirects++;
- */ icmp.args.address = args->address;
- break;
- case ICMP_TIME_REPLY:
- /* icmpOutTimestampReps++;
- */ icmp.args.echo.id = args->echo.id;
- icmp.args.echo.seq = args->echo.seq;
- break;
- case ICMP_DEST_UNREACH:
- if(icmp.code == ICMP_FRAG_NEEDED)
- icmp.args.mtu = args->mtu;
- /* icmpOutDestUnreachs++;
- */ break;
- }
- /* Now stick on the ICMP header */
- bp2 = htonicmp(&icmp,bp);
- dealmb( bp );
- /* if(bp2 == NULLBUF)
- return(-1);
- */ return( ip_send(&my_ip_addr,&ip->source,ICMP_PTCL,ip->tos,0,bp2,length,0,0));
- }
-
- /* ***************************************************************************
- * Function : Generate ICMP header in network byte order, link data,
- * compute checksum
- *
- * Inputs : pointer to icmp header structure in host format
- * and pointer to data to be appended
- *
- * Returns : Pointer to new frame in network format
- *
- * Operation : Well, there was this traveller in Transylvania,
- * -------------------------------------------------------------------------*/
- mhtyp *htonicmp(icmp,data)
- register ICMP *icmp;
- mhtyp *data;
- {
- register mhtyp *bp;
- unsigned short checksum;
- register unsigned putcnt;
- char *nxtchr, *cksum_ptr;
-
- bp = (mhtyp *)allocb();
- putchr( icmp->type, bp );
- putchr( icmp->code, bp );
- cksum_ptr = bp->nxtchr;
- put16( 0, bp ); /* Clear checksum */
-
- switch(icmp->type)
- {
- case ICMP_DEST_UNREACH:
- put16( 0, bp );
- if(icmp->code == ICMP_FRAG_NEEDED)
- /* Deering/Mogul max MTU indication */
- put16( icmp->args.mtu, bp);
- else
- put16( 0, bp);
- break;
- case ICMP_PARAM_PROB:
- putchr( icmp->args.pointer, bp );
- putchr( 0, bp );
- put16( 0, bp );
- break;
- case ICMP_REDIRECT:
- put16( icmp->args.address.Short[1], bp );
- put16( icmp->args.address.Short[0], bp );
- break;
- case ICMP_ECHO:
- case ICMP_ECHO_REPLY:
- case ICMP_TIMESTAMP:
- case ICMP_TIME_REPLY:
- case ICMP_INFO_RQST:
- case ICMP_INFO_REPLY:
- put16( icmp->args.echo.id, bp );
- put16( icmp->args.echo.seq, bp );
- break;
- default:
- put16( 0, bp );
- put16( 0, bp );
- break;
- }
- rwndmb( data );
- putcnt = data->putcnt;
- while( putcnt-- )
- putchr( getchr( data ) , bp );
-
- /* Compute checksum, and stash result */
- putcnt = bp->putcnt;
- rwndmb( bp );
- checksum = cksum(NULLHEADER,bp, bp->putcnt);
- bp->nxtchr = cksum_ptr;
- bp->putcnt = 2;
- put16( checksum, bp );
- bp->putcnt = putcnt;
- rwndmb( bp );
- return(bp);
- }
-
- /* ***************************************************************************
- * Function : Reduced icmp input routine for echo only
- *
- * Inputs : ip header decoded plus data in the ip frame
- *
- * Returns : nothing
- *
- * Operation : Perform a simple icmp input and ip receive function
- * to allow ping ( icmp echo request / reply )
- * If valid, uses ipsend to add to the send queue
- * -------------------------------------------------------------------------*/
- VOID icmp_input( ip, bp )
- register IP *ip;
- register mhtyp *bp;
- {
- mhtyp *tbp;
- register mhtyp *bp2;
- ICMP icmp;
- unsigned length, i;
-
- length = ip->length - IPLEN - ip->optlen;
- if( cksum( NULLHEADER, bp, length ) != 0 )
- return;
- if( bp->putcnt - bp->getcnt < 8 )
- return;
- icmp.type = getchr( bp );
- icmp.code = getchr( bp );
- if( icmp.type == ICMP_ECHO )
- {
- get16( bp );
- icmp.args.echo.id = get16( bp );
- icmp.args.echo.seq = get16( bp );
- icmp.type = ICMP_ECHO_REPLY;
- bp2 = allocb();
- if ( length > 8 )
- {
- i = length - 8;
- while( i-- )
- putchr( getchr( bp ), bp2 );
- }
- tbp = htonicmp( &icmp, bp2 );
- dealmb( bp2 );
- ip_send( &ip->dest, &ip->source, ICMP_PTCL,
- ip->tos, 0, tbp, length, 0, 0 );
- }
- }
-
- /* ***************************************************************************
- * Function : Perform end-around-carry adjustment
- *
- * Inputs : current checksum if using longs
- * ( if not, it uses a static structure ! )
- *
- * Returns : corrected unsigned integer checksum with carries
- *
- * Operation : Add the accumulated carry bits into the lower 16 bits
- * and keep doing it until you have no more carries
- * -------------------------------------------------------------------------*/
- #ifdef USELONG
- unsigned short eac(sum)
- long sum; /* Carries in high order 16 bits */
- {
- register unsigned short csum;
-
- while((csum = sum >> 16) != 0)
- sum = csum + (sum & 0xffffL);
- return((unsigned short) (sum & 0xffffl)); /* Chops to 16 bits */
- }
-
- #else
- unsigned short eac()
- {
- register unsigned short csum;
-
- while( ( csum = ip_cksum.Short[1] ) != 0 )
- {
- ip_cksum.Short[1] = 0;
- addsum( csum );
- }
- return( ip_cksum.Short[0] );
- }
- #endif
-
- /* ***************************************************************************
- * Function : Checksum an mhtyp, with optional pseudo-header
- *
- * Inputs : pseudo header, buffer to checksum and byte count
- *
- * Returns : unsigned integer checksum with eac corrected
- *
- * Operation : add up all bytes in a long, in perverse arpa way then eac
- * -------------------------------------------------------------------------*/
- unsigned short cksum(ph,m,len)
- register unsigned short len;
- register struct pseudo_header *ph;
- register mhtyp *m;
- {
- long sum;
- unsigned getcnt;
- char *nxtchr;
-
- #ifdef USELONG
- sum = 0L;
- #else
- ip_cksum.Short[0] = ip_cksum.Short[1] = 0;
- #endif
-
- /* Sum pseudo-header, if present */
- if(ph != NULLHEADER)
- {
- #ifdef USELONG
- sum = (unsigned)ph->source.Short[0];
- sum += (unsigned)ph->source.Short[1];
- sum += (unsigned)ph->dest.Short[0];
- sum += (unsigned)ph->dest.Short[1];
- sum += (unsigned)ph->protocol & 0xff;
- sum += (unsigned)ph->length;
- #else
- addsum( ph->source.Short[0] );
- addsum( ph->source.Short[1] );
- addsum( ph->dest.Short[0] );
- addsum( ph->dest.Short[1] );
- addsum( ph->protocol & 0xff );
- addsum( ph->length );
- #endif
- }
-
- getcnt = m->getcnt;
- nxtchr = m->nxtchr;
- while( len > 0 )
- {
- if( len > 1 )
- {
- #ifdef USELONG
- sum += (unsigned)get16( m );
- #else
- addsum( get16( m ) );
- #endif
- len -= 2;
- }
- else
- {
- #ifdef USELONG
- sum += ( (unsigned)getchr( m ) << 8 ) & 0xff00 ;
- #else
- addsum( ( getchr( m ) << 8 ) & 0xff00 );
- #endif
- len--;
- }
- }
- m->getcnt = getcnt;
- m->nxtchr = nxtchr;
- /* Do final end-around carry, complement and return */
- #ifdef USELONG
- return( (unsigned short)(~eac(sum) & 0xffff));
- #else
- return( ~eac() );
- #endif
- }
-
- /* ***************************************************************************
- * Function : for those systems that avoid longs, mask an ip address
- * off to (bits) bits
- *
- * Inputs : pointer to address and number of bits to leave
- *
- * Returns : nothing
- *
- * Operation : perform ip style 32 bit masking as two shorts.
- * -------------------------------------------------------------------------*/
-
- #ifndef USELONG
-
- VOID ip_mask( targt, bits )
- unsigned bits;
- ipaddr *targt;
- {
- register unsigned i = 32 - bits;
- register ipaddr *target = targt;
-
- if( i == 0 )
- return;
- else if( i < 16 )
- target->Short[0] &= ( ~0 << ( i ) );
- else
- {
- target->Short[0] = 0;
- if( i > 16 )
- target->Short[1] &= ( ~0 << ( i - 16 ) );
- }
- }
- #endif
-
- /* ***************************************************************************
- * Function : for those systems that avoid longs, add to checksum
- *
- * Inputs : 16 bit unsigned to add to 32 bit checksum
- *
- * Returns : nothing
- *
- * Operation : add the value to the static checksum ( unsigned long )
- * Note : for proper processors, #define does it with longs !
- * -------------------------------------------------------------------------*/
- #ifndef addsum
- #asm
- .z80
- public addsum_
-
- addsum_:
- pop hl
- pop de
- push de
- push hl
- ld hl,(ip_cksum_)
- add hl,de
- ld (ip_cksum_),hl
- ret nc
- ld hl,(ip_cksum_ + 2)
- inc hl
- ld (ip_cksum_ + 2 ),hl
- ret
-
- .8080
- #endasm
- #endif
-
- /* the following routines are needed for the arp protocol handler
- */
-
- /* ***************************************************************************
- * Function : Main handler for ARP requests from the network
- *
- * Inputs : pointer to the input frame from the L2 handler
- *
- * Returns : Nothing.
- *
- * Outputs : UI frame with the result of the processing ( if needed )
- *
- * Operation : Unpack the frame. Check it is OK, and is either for us
- * or for a published entry or a revarp request we can deal
- * with. If it is, form the reply and send a UI frame.
- * -------------------------------------------------------------------------*/
-
- VOID arp_service( mhbp )
- mhtyp *mhbp;
- {
- unsigned char arp_not_revarp;
- char *ptr;
- register mhtyp *mbhd = mhbp;
- register ARP_TAB *ap;
- register unsigned i;
- ARP_TAB_MB *atp;
-
- if( !ARPrunning || (unsigned char)mbhd->pid != PID_ARP )
- return;
- if(( arp.hardware = get16( mbhd )) != ARP_AX25 )
- {
- /* arp_stat.badtype++; */
- return;
- }
- if( (arp.protocol = get16( mbhd ) ) != PID_IP )
- {
- /* arp_stat.badtype++; */
- return;
- }
- arp.hwalen = getchr( mbhd );
- arp.pralen = getchr( mbhd );
- if( arp.hwalen > MAXHWALEN || arp.pralen != sizeof( ipaddr ) )
- {
- /* arp_stat.badlen++; */
- return;
- }
- arp.opcode = get16( mbhd );
- getfid( arp.shwaddr, mbhd );
- arp.sprotaddr.Short[1] = get16( mbhd );
- arp.sprotaddr.Short[0] = get16( mbhd );
- getfid( arp.thwaddr, mbhd );
- arp.tprotaddr.Short[1] = get16( mbhd );
- arp.tprotaddr.Short[0] = get16( mbhd );
- if( cmpid( arp.shwaddr, QST ) )
- {
- /* arp_stat.badaddr++; */
- return;
- }
-
- ap = res_arp( &arp.sprotaddr, arp.hardware );
-
- if( ((i=is_my_ip_addr( &arp.tprotaddr)) && ap == NULLARP )
- ||
- ( ap != NULLARP && ap->timer != 0 ) )
- arp_add( &arp.sprotaddr, arp.hardware, arp.shwaddr, 0, ARPtimer, 0 );
-
- if( arp.opcode == REVARP_REQUEST
- ||
- ( arp.opcode == ARP_REQUEST
- &&
- ( ( i /* = is_my_ip_addr( &arp.tprotaddr ) */ )
- ||
- ( ( ap = res_arp( &arp.tprotaddr, arp.hardware )) != NULLARP
- && ap->publish_flag
- )
- )
- )
- )
- {
- arp_not_revarp = ( arp.opcode == ARP_REQUEST );
- if( !arp_not_revarp )
- for( atp = ( ARP_TAB_MB * )Arp_tab.lnext;
- atp != ( ARP_TAB_MB * )&Arp_tab.lnext;
- atp = ( ARP_TAB_MB * )atp->link.lnext )
- if( ( i = cmpid( (ap=&(atp->arp))->callsign, arp.thwaddr ) ) )
- break;
- if( arp_not_revarp || ( i && ap->publish_flag ) )
- {
- if( arp_not_revarp )
- {
- cpyid( arp.thwaddr, arp.shwaddr );
- /* if( arp.hardware == ARP_AX25 ) */
- arp.thwaddr[arp.hwalen - 1 ] |= 1;
- }
- cpyid( arp.shwaddr, i ? myid : ap->callsign );
- #ifdef USELONG
- arp.tprotaddr.Long = arp_not_revarp ?
- arp.sprotaddr.Long : ap->dest.Long;
- arp.sprotaddr.Long = i ?
- my_ip_addr.Long : ap->dest.Long;
- #else
- arp.tprotaddr.Short[1] = arp_not_revarp ?
- arp.sprotaddr.Short[1] : ap->dest.Short[1];
- arp.tprotaddr.Short[0] = arp_not_revarp ?
- arp.sprotaddr.Short[0] : ap->dest.Short[0];
- arp.sprotaddr.Short[1] = i ?
- my_ip_addr.Short[1] : ap->dest.Short[1];
- arp.sprotaddr.Short[0] = i ?
- my_ip_addr.Short[0] : ap->dest.Short[0];
- #endif
- arp.opcode = arp_not_revarp ? ARP_REPLY : REVARP_REPLY;
- arp_send( mhbp->l2port, arp.thwaddr );
- /* Arp_stat.inreq++; */
- }
- }
- }
-
- /* ***************************************************************************
- * Function : Send an ARP request/response frame to specified port ( L2 AX25 )
- *
- * Inputs : pointer to the host format arp frame and L2 port number
- *
- * Returns : Nothing.
- *
- * Outputs : UI frame with the ARP request
- *
- * -------------------------------------------------------------------------*/
-
-
- arp_send( port, hwaddr )
- unsigned port;
- char *hwaddr;
- {
- register mhtyp *mbhd;
-
- mbhd = allocb();
- put16( arp.hardware, mbhd );
- put16( arp.protocol, mbhd );
- putchr( arp.hwalen, mbhd );
- putchr( arp.pralen, mbhd );
- put16( arp.opcode, mbhd );
- putfid( arp.shwaddr, mbhd );
- put16( arp.sprotaddr.Short[1], mbhd );
- put16( arp.sprotaddr.Short[0], mbhd );
- putfid( arp.thwaddr, mbhd );
- put16( arp.tprotaddr.Short[1], mbhd );
- put16( arp.tprotaddr.Short[0], mbhd );
- /* if( mbhd == NULLBUF ) return; */
- mbhd->pid = PID_ARP;
- rwndmb( mbhd );
- sdui( nodigi, hwaddr, myid, port, mbhd );
- dealmb( mbhd );
- }
-
- arp_request( gw, hwtype, port )
- ipaddr *gw;
- unsigned hwtype;
- unsigned port;
- {
- register unsigned i;
- register ipaddr *gateway = gw;
-
- arp.hardware = hwtype;
- arp.protocol = PID_IP;
- arp.hwalen = L2IDLEN;
- arp.pralen = sizeof( ipaddr );
- arp.opcode = ARP_REQUEST;
- cpyid( arp.shwaddr, myid );
- #ifdef USELONG
- arp.sprotaddr.Long = my_ip_addr.Long;
- arp.tprotaddr.Long = gateway->Long;
- #else
- arp.sprotaddr.Short[0] = my_ip_addr.Short[0];
- arp.sprotaddr.Short[1] = my_ip_addr.Short[1];
- arp.tprotaddr.Short[0] = gateway->Short[0];
- arp.tprotaddr.Short[1] = gateway->Short[1];
- #endif
- for( i=0; i<L2IDLEN; i++ )
- arp.thwaddr[i] = 0;
- arp_send( port, QST );
- }
-